package com.kly.user.task;

import cn.hutool.core.net.NetUtil;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.common.eventbus.AsyncEventBus;
import com.kly.user.config.NacosValueConfig;
import com.kly.user.db.dao.*;
import com.kly.user.db.entity.UserEntity;
import com.kly.user.db.entity.UserOnlineLogEntity;
import com.kly.user.enums.OnlineStatus;
import com.kly.user.enums.UserType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Component
public class OnlineStatusCheckTask {

    private static Log logger = LogFactory.getLog(OnlineStatusCheckTask.class);

    @NacosValue(value = "${normal.user.online.check.value:2}", autoRefreshed = true)
    private Integer userOnlineMaxGapValue;

    @NacosValue(value = "${chatter.user.online.check.value:2}", autoRefreshed = true)
    private Integer chatterOnlineMaxGapValue;
    @NacosValue(value = "${user.online.to.offline.value:2}", autoRefreshed = true)
    private Integer userOnlineToOfflineValue;
    @NacosValue(value = "${open.not.bind.chatter.model.online.switch:true}", autoRefreshed = true)
    private boolean notBindMobileActiveSwitch;

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserOnlineLogDao userOnlineLogDao;

    @Autowired
    private UserChatterMappingDao userChatterMappingDao;

//    @NacosValue(value = "${task.job.executor.ip}", autoRefreshed = true)
    @NacosValue(value = "${master.task.job.executor.ip}", autoRefreshed = true)
    private String taskJobExecutor;
//    @NacosValue(value = "${master.task.job.executor.ip}", autoRefreshed = true)
//    private String masterJobExecutor;
    @NacosValue(value = "${enable.online.switch:false}", autoRefreshed = true)
    private Boolean enableSwitch;

    private String localIP = NetUtil.getLocalhostStr();
    @NacosValue(value = "${push.enable.switch:false}", autoRefreshed = true)
    private Boolean pushEnable;

    @NacosValue(value = "${updateAllCmOnline:false}", autoRefreshed = true)
    private Boolean updateAllCmOnline;
    @NacosValue(value = "${checkNormalUserSwitch:false}", autoRefreshed = true)
    private Boolean checkNormalUserSwitch;
    @NacosValue(value = "${checkMSwitch:false}", autoRefreshed = true)
    private Boolean checkMSwitch;
    @Resource
    private NacosValueConfig nacosValueConfig;

    @Resource
    UserConversationDao userConversationDao;
    @Resource
    UserWlmDao userWlmDao;
    @Resource
    UserPreHomepageDao userPreHomepageDao;
    @Resource
    AsyncEventBus pushEventBus;

    /**
     * 绑定了model的chatter就是CM
     * 每五分钟检查一次在线model的状态
     * 如果离线时间大于chatterOnlineMaxGapValue 则变为离线
     * 如果最近在线时间在两分钟内，我们设为在线状态
     */
    @Scheduled(fixedDelay = 1000 * 120)
    public void cmOnlineToOffLine() {
        if (!enableSwitch) {
            logger.info("=============cmOnlineToOffLine, enableSwitch:{}", enableSwitch);
            return;
        }
        if (!checkMSwitch) {
            logger.info("=============cmOnlineToOffLine, checkMSwitch:{}", checkMSwitch);
            return;
        }

        if (!taskJobExecutor.contains(localIP)) {
            logger.info("=============cmOnlineToOffLine NotTaskJobExecutor, currentLocalAddress:{}, onlyExecuteTaskIn:{}", localIP, taskJobExecutor);
            return;
        }

        try {
            long start = System.currentTimeMillis();
            logger.info("=============cmOnlineToOffLine, 开始处理CM的下线问题 开始");
            List<UserEntity> onlineCm = userDao.getAllModelsAssignedChatter(OnlineStatus.ONLINE_STATUS.getType());
            logger.info("=============cmOnlineToOffLine, 在线数量:{}", onlineCm.size());
            onlineCm.forEach(userEntity -> {
                if (userEntity.getOnlineTimestamp() == null) {
                    logger.info("=============cmOnlineToOffLine, 没有 onlinetimestamp值，默认设为下线，usercODE:{}", userEntity.getUserCode());
                    updateOnlineStatus(userEntity, OnlineStatus.OFFLINE_STATUS);
                    return;
                }
                try {
                    long aLong = Long.parseLong(userEntity.getOnlineTimestamp());
                    long timeMs = Calendar.getInstance().getTimeInMillis() - aLong;
                    long mins = timeMs / 60000;
                    logger.info("=============cmOnlineToOffLine判定用户状态的任务1 准备更新状态1==================,userCode:{},mins:{},a:{},b:{}", userEntity.getUserCode(), mins, aLong, timeMs);
                    if (mins > chatterOnlineMaxGapValue) {
                        logger.info("=============cmOnlineToOffLine判定用户状态的任务1 需要下线==================,userCode:{},mins:{},a:{},b:{},下线", userEntity.getUserCode(), mins, aLong, timeMs);
                        updateOnlineStatus(userEntity, OnlineStatus.OFFLINE_STATUS);

                        //CM下线，对应的model也需要下线

                    } else {
                        logger.info("=============cmOnlineToOffLine判定用户状态的任务1 不需要下线==================,userCode:{},mins:{},a:{},b:{},保持在线", userEntity.getUserCode(), mins, aLong, timeMs);
                    }

                } catch (NumberFormatException e) {
                    logger.error("=============cmOnlineToOffLine判定用户状态的任务2 发生异常==================", e);
                }
            });

            logger.info("=============cmOnlineToOffLine, 开始处理CM的下线问题 结束，cost:{}", System.currentTimeMillis() - start);
        } catch (Exception e) {
            logger.error("=============cmOnlineToOffLine判定用户状态的任务3  cmOnlineToOffLine error==================", e);
        }
        try {
            checkModelNoBindChatter();
        } catch (Exception e) {
            logger.error("=============cmOnlineToOffLine判定用户状态的任务4  checkModelNoBindChatter error==================", e);
        }
        try {
            recordChatterOnlineLog();
        } catch (Exception e) {
            logger.error("=============cmOnlineToOffLine判定用户状态的任务5  recordChatterOnlineLog error==================", e);
        }
    }

    /**
     * 没有绑定chatter的Model都跟着设置的工作时间走
     */
    private void checkModelNoBindChatter() {
        logger.info("=============checkModelNoBindChatter判定用户状态的任务 MODEL==================");
        if (!notBindMobileActiveSwitch) {
            logger.info("=============checkModelNoBindChatter判定用户状态的任务 MODEL switch not open==================");
            return;
        }

        List<UserEntity> usersByUserType = userDao.getAllModelsNotAssignedChatter(null);

        logger.info("=============checkModelNoBindChatter判定用户状态的任务 MODEL==================,size:{}", usersByUserType.size());
        usersByUserType.forEach(userEntity -> {
            try {
                int online = userEntity.getOnline();
                if (userEntity.getOnlineTimeStart() != null && userEntity.getOnlineTimeEnd() != null) {
                    logger.info("=============checkModelNoBindChatter判定用户状态的任务 设置了在线区间==================,userCode:{}", userEntity.getUserCode());
                    int startHour = DateUtil.getHour(userEntity.getOnlineTimeStart());
                    int endHour = DateUtil.getHour(userEntity.getOnlineTimeEnd());
                    int hour = DateUtil.getHour();
                    online = (hour >= startHour && hour <= endHour) ? OnlineStatus.ONLINE_STATUS.getType() : OnlineStatus.OFFLINE_STATUS.getType();
                }

                if (userEntity.getOnlineTimeStart() == null || userEntity.getOnlineTimeEnd() == null) {
                    logger.info("=============checkModelNoBindChatter判定用户状态的任务 没有在线区间设置，那么职位下线状态==================,userCode:{}", userEntity.getUserCode());
                    online = OnlineStatus.OFFLINE_STATUS.getType();
                }

                if (online != userEntity.getOnline()) {
                    logger.info("=============checkModelNoBindChatter判定用户状态的任务 状态有更新==================,userCode:{}", userEntity.getUserCode());
                    updateOnlineStatus(userEntity, OnlineStatus.fromType(online));
                }

            } catch (NumberFormatException e) {
                logger.error("=============checkModelNoBindChatter判定用户状态的任务 MODEL==================", e);
            }
        });
    }

    private void recordChatterOnlineLog() {
        logger.info("=============recordChatterOnlineLog判定用户状态的任务 CHATTER==================");
        List<UserEntity> usersByUserType = userDao.getUsersByUserType(UserType.CHATTER.getType());
        logger.info("=============recordChatterOnlineLog判定用户状态的任务 CHATTER==================,size:{}", usersByUserType.size());
        usersByUserType.forEach(userEntity -> {
            try {
                userOnlineLogDao.insert(new UserOnlineLogEntity().setOnline(userEntity.getOnline()).setUserCode(userEntity.getUserCode()).setUserType(userEntity.getUserType()).setCreateHour(DateUtil.getHour()).setCreateMin(DateUtil.getMinute()).setCreateDt(new Date()));
            } catch (NumberFormatException e) {
                logger.error("=============recordChatterOnlineLog判定用户状态的任务 CHATTER==================", e);
            }
        });
    }

    private void updateOnlineStatus(UserEntity userEntity, OnlineStatus onlineStatus) {

        // 更新在线状态
        userDao.updateOnline(userEntity.getUserCode(), onlineStatus.getType());


    }


    /**
     * 20230927 只处理在线转离线，离线转在线改为长链接处理
     */
    @Scheduled(fixedDelay = 1000 * 15)
    public void onlineToOfflineTask() {
        logger.info("=============onlineToOfflineTask 开始");
        long start = System.currentTimeMillis();

        if (!enableSwitch) {
            logger.info("=============onlineToOfflineTask, enableSwitch:{}", enableSwitch);
            return;
        }
        if (!checkNormalUserSwitch) {
            logger.info("=============onlineToOfflineTask, checkNormalUserSwitch:{}", checkNormalUserSwitch);
            return;
        }

        if (!taskJobExecutor.contains(localIP)) {
            logger.info("=============onlineToOfflineTask NotTaskJobExecutor, currentLocalAddress:{}, onlyExecuteTaskIn:{}", localIP, taskJobExecutor);
            return;
        }

//        final int offlineUserNum = userDao.onlineToOffLine(userOnlineToOfflineValue);
        // 配置保持在线的用户，下线任务刷新离线状态时不会更新
        final int offlineUserNum = userDao.onlineToOffLineV2(userOnlineToOfflineValue, nacosValueConfig.keepOnlineUserCodes());
        logger.info("=============onlineToOfflineTask 下线用户数:{},maxLiveMins:{},cost:{}", offlineUserNum,userOnlineToOfflineValue,System.currentTimeMillis()-start);
        final int offlineChatterNum = userDao.onlineToOffLineChatter(chatterOnlineMaxGapValue);
        logger.info("=============onlineToOfflineTask 下线主播数数:{},maxLiveMins:{},cost:{}", offlineChatterNum,chatterOnlineMaxGapValue,System.currentTimeMillis()-start);
        final int offLineModel = userDao.onlineToOffLineModel(chatterOnlineMaxGapValue);
        logger.info("=============onlineToOfflineTask 下线主播数数:{},maxLiveMins:{},cost:{}", offLineModel,chatterOnlineMaxGapValue,System.currentTimeMillis()-start);

        logger.info("=============onlineToOfflineTask 结束");
        // 添加用户在线日志
        try {
            userOnlineLogDao.addUserOnlineLog();
        } catch (Exception e) {
            logger.error("====onlineToOfflineTask 添加用户在线日志异常", e);
        }

    }

}
